﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;

namespace Devonline.AspNetCore;

/// <summary>
/// excel 导入导出操作的服务
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TKey">键类型</typeparam>
public class ExcelService<TDbContext, TKey> : ServiceBase<TDbContext, TKey>, IExcelService<TDbContext, TKey> where TDbContext : DbContext where TKey : IConvertible
{
    private readonly IExcelExportService _excelExportService;
    private readonly IExcelImportService<TDbContext, TKey> _excelImportService;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="context"></param>
    /// <param name="logger"></param>
    /// <param name="cache"></param>
    /// <param name="httpContextAccessor"></param>
    /// <param name="appSetting"></param>
    public ExcelService(
        TDbContext context,
        ILogger<ExcelService<TDbContext, TKey>> logger,
        IDistributedCache cache,
        IHttpContextAccessor httpContextAccessor,
        AppSetting appSetting,
        IExcelExportService excelExportService,
        IExcelImportService<TDbContext, TKey> excelImportService
        ) : base(context, logger, cache, httpContextAccessor, appSetting)
    {
        _excelExportService = excelExportService;
        _excelImportService = excelImportService;
    }

    /// <summary>
    /// 从 excel 导入数据
    /// 需要 FileName(必须), SheetIndex(非必须) 和 SheetName(非必须) 参数
    /// 导入结果保存在 ExcelData 的 Data 字段, 错误信息保存在 Messages 字段
    /// get data, excel row and column index from 1
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="excelData">excel 数据对象</param>
    public virtual void Import<TEntitySet>(ExcelData<TEntitySet> excelData) where TEntitySet : class, new() => _excelImportService.Import(excelData);
    /// <summary>
    /// 使用文件名构造默认 excel 数据对象进行导入
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="fileName">excel 文件名</param>
    public virtual void Import<TEntitySet>(string fileName) where TEntitySet : class, new() => _excelImportService.Import<TEntitySet>(fileName);
    /// <summary>
    /// 导入 excel 数据并在无错情况下直接入库保存
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="excelData">excel 数据对象</param>
    /// <returns></returns>
    public virtual async Task<IActionResult> ImportAsync<TEntitySet>(ExcelData<TEntitySet> excelData) where TEntitySet : class, IEntitySet<TKey>, new() => await _excelImportService.ImportAsync(excelData);
    /// <summary>
    /// 导入 excel 数据并在无错情况下直接入库保存
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="fileName">excel 文件名</param>
    /// <returns></returns>
    public virtual async Task<IActionResult> ImportAsync<TEntitySet>(string fileName) where TEntitySet : class, IEntitySet<TKey>, new() => await _excelImportService.ImportAsync<TEntitySet>(fileName);

    /// <summary>
    /// 导出数据到 excel
    /// 需要 Data(必须), Columns(非必须) 和 SheetName(非必须) 参数
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="excelData">excel 数据对象</param>
    public virtual IExcelExportService Export<TEntitySet>(ExcelData<TEntitySet> excelData) => _excelExportService.Export(excelData);
    /// <summary>
    /// 导出数据到 excel, 此方法会按默认参数构造 ExcelData 并导出
    /// 需要 Data(必须), Columns(非必须) 和 SheetName(非必须) 参数
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="Data">要导出的数据集合</param>
    public virtual IExcelExportService Export<TEntitySet>(IEnumerable<TEntitySet> Data) => _excelExportService.Export(Data);
    /// <summary>
    /// 在链式循环导出时, 最后一个直接导出为文件的方法
    /// <param name="fileName">导出的 Excel 文件名, 如果为空, 则使用最后一个 ExcelData 的文件名</param>
    /// </summary>
    /// <returns></returns>
    public virtual async Task<IActionResult> ExportAsync(string? fileName = null) => await _excelExportService.ExportAsync(fileName);
    /// <summary>
    /// 单个数据集直接导出到一个 excel 文件, 并直接返回
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="excelData">excel 数据对象</param>
    /// <returns></returns>
    public virtual async Task<IActionResult> ExportAsync<TEntitySet>(ExcelData<TEntitySet> excelData) => await _excelExportService.ExportAsync(excelData);
    /// <summary>
    /// 导出数据到 excel, 此方法会按默认参数构造 ExcelData 并导出
    /// 需要 Data(必须), Columns(非必须) 和 SheetName(非必须) 参数
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="Data">要导出的数据集合</param>
    public virtual async Task<IActionResult> ExportAsync<TEntitySet>(IEnumerable<TEntitySet> Data) => await _excelExportService.ExportAsync(Data);
    /// <summary>
    /// 获取导出处理过程中存在于内存中的 excel 文件数据流
    /// </summary>
    /// <returns></returns>
    public virtual async Task<byte[]> GetContentsAsync() => await _excelExportService.GetContentsAsync();
}

/// <summary>
/// excel 导入导出操作的服务
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
public class ExcelService<TDbContext> : ExcelService<TDbContext, string>, IExcelService<TDbContext> where TDbContext : DbContext
{
    public ExcelService(
        TDbContext context,
        ILogger<ExcelService<TDbContext>> logger,
        IDistributedCache cache,
        IHttpContextAccessor httpContextAccessor,
        AppSetting appSetting,
        IExcelExportService excelExportService,
        IExcelImportService<TDbContext> excelImportService
        ) : base(context, logger, cache, httpContextAccessor, appSetting, excelExportService, excelImportService) { }
}